# -*- coding: utf-8 -*-
"""
random subspace + ensemble + semi
通过随机子空间方法初始化多个分类器
每个分类器不断的从无标签数据中选择高置信度数据重新训练分类器
直到无标签数据集为空
"""
from utils.SemiSupervisedClassifier import SemiSupervisedClassifier
from utils import load_txt_regex
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.utils import check_random_state
import numpy as np
from utils import gen_data


class SelfTrainingClassifier3(SemiSupervisedClassifier):

    def __init__(self, base_estimator, unlabeled_data, unlabeled_label, n_estimator=10, cycles=50, random_state=None):
        super().__init__(base_estimator, unlabeled_data, unlabeled_label, random_state)
        self.n_estimator = n_estimator
        self.feat_inx = []          # 记录选择的特征索引下标
        self.cycles = cycles

    def predict(self, X):
        data_selected = self._select_feature(X)
        predictions = [self.estimators_[i].predict(data_selected[i]) for i in range(len(self.estimators_))]
        predictions = np.array(predictions)
        vote_predictions = np.sum(predictions, axis=0)
        return np.where(vote_predictions > 0, 1, -1)

    def init_estimators(self, X, y):
        self.estimators_ = []
        clazz = getattr(self.base_estimator, '__class__')
        params = self.base_estimator.get_params()
        self._select_feature_index(X)
        for i in range(self.n_estimator):
            estimator = clazz(**params)
            samples, labels = self._bootstrap_sampling(X, y)
            samples_selected = samples[:, self.feat_inx[i]]
            estimator.fit(samples_selected, labels)
            self.estimators_.append(estimator)

    def _update_estimator(self, X, y):
        for cycle in range(self.cycles):
            for i in range(len(self.estimators_)):
                unlabeled_pred = self.estimators_[i].predict(unlabeled_data[:, self.feat_inx[i]])
                h_X, h_y = self._bootstrap_sampling(self.unlabeled_data, unlabeled_pred)
                h_X = np.concatenate((X, h_X), axis=0)
                h_y = np.concatenate((y, h_y), axis=0)
                self.estimators_[i].fit(h_X[:, self.feat_inx[i]], h_y)

    def _select_feature_index(self, X, size=None):
        num, dim = X.shape
        if size is None:
            size = int(np.sqrt(dim))
        index = []
        random_state = check_random_state(None)
        for i in range(self.n_estimator):
            index.append(random_state.choice(range(dim), size))
        self.feat_inx = index
        return index

    def _select_feature(self, X):
        if len(self.feat_inx) <= 0:
            self._select_feature_index(X)
        data_selected = []
        for inx in self.feat_inx:
            data_selected.append(X[:, inx])
        return data_selected


if __name__ == '__main__':
    path = r'../data/csv/'
    name = 'banana.csv'
    train_data, train_label, test_data, test_label, labeled_data, labeled_label, unlabeled_data, unlabeled_label \
        = gen_data(path+name, unlabeled_rate=0.8, random_state=919)

    estimator = SVC()
    sel = SelfTrainingClassifier3(estimator, unlabeled_data, unlabeled_label, n_estimator=10)
    sel.fit(labeled_data, labeled_label)
    print(sel.score(test_data, test_label))
